package com.guan.job.handler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.guan.common.core.constants.CacheConstants;
import com.guan.common.core.constants.Constants;
import com.guan.job.domain.exam.Exam;
import com.guan.job.domain.message.Message;
import com.guan.job.domain.message.MessageText;
import com.guan.job.domain.message.vo.MessageTextVO;
import com.guan.job.domain.user.UserScore;
import com.guan.job.mapper.ExamMapper;
import com.guan.job.mapper.UserExamMapper;
import com.guan.job.mapper.UserSubmitMapper;
import com.guan.job.service.IMessageService;
import com.guan.job.service.IMessageTextService;
import com.guan.ojcommonredis.service.RedisService;
import com.xxl.job.core.handler.annotation.XxlJob;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class ExamXxlHandler {

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Autowired
    private UserExamMapper userExamMapper;

    @Resource
    private RedisService redisService;

    @Resource
    private IMessageTextService messageTextService;

    @Resource
    private IMessageService messageService;

    @XxlJob("examListOrganizeHandler")
    public void examListOrganizeHandler() {
        log.info("========================= examListOrganizeHandler =============================");
        //未完赛竞赛列表
        List<Exam> unFinishExamList = examMapper.selectList(new
                LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime,
                        Exam::getEndTime)
                .gt(Exam::getEndTime, LocalDateTime.now())
                .eq(Exam::getStatus, Constants.TRUE)
                .orderByDesc(Exam::getCreateTime));
        // 刷新
        refreshCache(getUnFinishExamListKey(), unFinishExamList);
        //历史竞赛列表
        List<Exam> finishExamList = examMapper.selectList(new
                LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime,
                        Exam::getEndTime)
                .le(Exam::getEndTime, LocalDateTime.now())
                .eq(Exam::getStatus, Constants.TRUE)
                .orderByDesc(Exam::getCreateTime));
        // 刷新
        refreshCache(getFinishExamListKey(), finishExamList);
    }


    @XxlJob("examResultHandler")
    public void examResultHandler(){
        log.info("========================= 竞赛结束相关定时任务开启 =============================");
        // 获取当前时间和前一天的时间范围
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startOfYesterday = now.minusDays(1).toLocalDate().atStartOfDay(); // 前一天 0:00
        LocalDateTime endOfYesterday = startOfYesterday.plusDays(1).minusNanos(1);      // 前一天 23:59:59

        // 筛选出前一天内结束的所有竞赛
        List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle)
                .eq(Exam::getStatus, Constants.TRUE) // 状态为发布的竞赛
                .ge(Exam::getEndTime, startOfYesterday)
                .le(Exam::getEndTime, endOfYesterday));

        // 如果没有符合条件的竞赛，直接返回
        if (CollectionUtil.isEmpty(examList)) {
            return;
        }

        // 提取竞赛ID的集合
        Set<Long> examIdSet = examList.stream().map(Exam::getExamId).collect(Collectors.toSet());

        // 查询所有用户在这些竞赛中的排名和得分情况
        List<UserScore> userScoreList = userSubmitMapper.selectUserScoreList(examIdSet);

        // 根据竞赛ID对用户得分情况进行分组
        Map<Long, List<UserScore>> userScoreMap = userScoreList.stream()
                .collect(Collectors.groupingBy(UserScore::getExamId));

        // 创建站内信通知用户
        createMessage(examList, userScoreMap);
        log.info("========================= 竞赛结束相关定时任务结束 =============================");
    }

    private void createMessage(List<Exam> examList, Map<Long, List<UserScore>> userScoreMap) {
        List<MessageText> messageTextList = new ArrayList<>();
        List<Message> messageList = new ArrayList<>();
        for (Exam exam : examList) {
            Long examId = exam.getExamId();
            List<UserScore> userScoreList = userScoreMap.get(examId);
            int totalUser = userScoreList.size();
            int examRank = 1;
            for (UserScore userScore : userScoreList) {
                String msgTitle =  exam.getTitle() + "——排名情况";
                String msgContent = "您所参与的竞赛：" + exam.getTitle()
                        + "，本次参与竞赛一共" + totalUser + "人， 您排名第"  + examRank + "名！";
                userScore.setExamRank(examRank);
                MessageText messageText = new MessageText();
                messageText.setMessageTitle(msgTitle);
                messageText.setMessageContent(msgContent);
                messageText.setCreateBy(Constants.SYSTEM_USER_ID);
                messageTextList.add(messageText);
                Message message = new Message();
                message.setSendId(Constants.SYSTEM_USER_ID);
                message.setCreateBy(Constants.SYSTEM_USER_ID);
                message.setRecId(userScore.getUserId());
                messageList.add(message);
                examRank++;
            }
            userExamMapper.updateUserScoreAndRank(userScoreList);
            redisService.rightPushAll(getExamRankListKey(examId), userScoreList);
        }
        messageTextService.batchInsert(messageTextList);
        Map<String, MessageTextVO> messageTextVOMap = new HashMap<>();
        for (int i = 0; i < messageTextList.size(); i++) {
            MessageText messageText = messageTextList.get(i);
            MessageTextVO messageTextVO = new MessageTextVO();
            BeanUtil.copyProperties(messageText, messageTextVO);
            String msgDetailKey = getMsgDetailKey(messageText.getTextId());
            messageTextVOMap.put(msgDetailKey, messageTextVO);
            Message message = messageList.get(i);
            message.setTextId(messageText.getTextId());
        }
        messageService.batchInsert(messageList);
        //redis 操作
        Map<Long, List<Message>> userMsgMap = messageList.stream().collect(Collectors.groupingBy(Message::getRecId));
        Iterator<Map.Entry<Long, List<Message>>> iterator = userMsgMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Long, List<Message>> entry = iterator.next();
            Long recId = entry.getKey();
            String userMsgListKey = getUserMsgListKey(recId);
            List<Long> userMsgTextIdList = entry.getValue().stream().map(Message::getTextId).toList();
            redisService.rightPushAll(userMsgListKey, userMsgTextIdList);
        }
        redisService.multiSet(messageTextVOMap);
    }


    public void refreshCache(String examListKey, List<Exam> examList) {
        if (CollectionUtil.isEmpty(examList)) {
            return;
        }
        Map<String, Exam> examMap = new HashMap<>();
        List<Long> examIdList = new ArrayList<>();
        for (Exam exam : examList) {
            examMap.put(getDetailKey(exam.getExamId()), exam);
            examIdList.add(exam.getExamId());
        }
        redisService.multiSet(examMap); //刷新详情缓存
        redisService.deleteObject(examListKey);
        redisService.rightPushAll(examListKey, examIdList); //刷新列表缓
    }


    private String getUnFinishExamListKey(){
        return CacheConstants.EXAM_LIST_UNFINISHED;
    }

    private String getFinishExamListKey(){
        return CacheConstants.EXAM_LIST_FINISHED;
    }

    private String getDetailKey(Long examId) {
        return CacheConstants.EXAM_DETAIL + examId;
    }


    private String getUserMsgListKey(Long userId) {
        return CacheConstants.USER_MESSAGE_LIST + userId;
    }

    private String getMsgDetailKey(Long textId) {
        return CacheConstants.MESSAGE_DETAIL + textId;
    }

    private String getExamRankListKey(Long examId) {
        return CacheConstants.EXAM_RANK_LIST + examId;
    }

}
